﻿<!--
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
-->
    
<UserControl 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"

  xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
  xmlns:samples="clr-namespace:System.Windows.Controls.Samples"
  xmlns:system="clr-namespace:System;assembly=mscorlib"
  x:Class="System.Windows.Controls.Samples.CustomSeriesSample">
    <StackPanel>

        <!-- Basic Examples -->
        <ContentControl Content="Basic Examples" Style="{StaticResource Header}"/>
        <toolkit:WrapPanel>
            <Grid Style="{StaticResource WrapperStyle}">
                <chartingToolkit:Chart Title="Constant">
                    <chartingToolkit:Chart.Series>
                        <chartingToolkit:ScatterSeries
                          Title="Particulate Levels"
                          ItemsSource="{Binding LevelsInRainfall, Source={StaticResource ParticulateLevel}}"
                          IndependentValueBinding="{Binding Rainfall}"
                          DependentValueBinding="{Binding Particulate}" />
                        <samples:FunctionSeries
                          Function="110"
                          Title="f(x) = 110"
                          LineBrush="Blue"
                          LineThickness="2" />
                    </chartingToolkit:Chart.Series>
                </chartingToolkit:Chart>
            </Grid>
            
            <Grid Style="{StaticResource WrapperStyle}">
                <chartingToolkit:Chart Title="Linear">
                    <chartingToolkit:Chart.Series>
                        <chartingToolkit:ScatterSeries
                          Title="Particulate Levels"
                          ItemsSource="{Binding LevelsInRainfall, Source={StaticResource ParticulateLevel}}"
                          IndependentValueBinding="{Binding Rainfall}"
                          DependentValueBinding="{Binding Particulate}" />
                        <samples:FunctionSeries
                          Function="110 + x"
                          Title="f(x) = 110 + x"
                          LineBrush="Green"
                          LineThickness="2" />
                    </chartingToolkit:Chart.Series>
                </chartingToolkit:Chart>
            </Grid>
            
            <Grid Style="{StaticResource WrapperStyle}">
                <chartingToolkit:Chart Title="Quadratic">
                    <chartingToolkit:Chart.Series>
                        <chartingToolkit:ScatterSeries
                          Title="Particulate Levels"
                          ItemsSource="{Binding LevelsInRainfall, Source={StaticResource ParticulateLevel}}"
                          IndependentValueBinding="{Binding Rainfall}"
                          DependentValueBinding="{Binding Particulate}" />
                        <samples:FunctionSeries
                          Function="110 + (x - 4)^2"
                          LineBrush="Red"
                          LineThickness="1">
                            <samples:FunctionSeries.Title>
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock Grid.Row="1" Text="f(x) = 110 + (x - 4)" Margin="0 4 0 0" />
                                    <TextBlock Grid.Column="1" Text="2" FontSize="8" Margin="0"  />
                                </StackPanel>
                            </samples:FunctionSeries.Title>
                        </samples:FunctionSeries>
                    </chartingToolkit:Chart.Series>
                </chartingToolkit:Chart>
            </Grid>
            
            <Grid Style="{StaticResource WrapperStyle}">
                <chartingToolkit:Chart Title="Cubic">
                    <chartingToolkit:Chart.Series>
                        <chartingToolkit:ScatterSeries
                          Title="Particulate Levels"
                          ItemsSource="{Binding LevelsInRainfall, Source={StaticResource ParticulateLevel}}"
                          IndependentValueBinding="{Binding Rainfall}"
                          DependentValueBinding="{Binding Particulate}" />
                        <samples:FunctionSeries
                          Function="110 + (x - 4)^3"
                          LineBrush="Black"
                          LineThickness="3">
                            <samples:FunctionSeries.Title>
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock Grid.Row="1" Text="f(x) = 110 + (x - 4)" Margin="0 4 0 0" />
                                    <TextBlock Grid.Column="1" Text="3" FontSize="8" Margin="0"  />
                                </StackPanel>
                            </samples:FunctionSeries.Title>
                        </samples:FunctionSeries>
                    </chartingToolkit:Chart.Series>
                </chartingToolkit:Chart>
            </Grid>
            
            <Grid Style="{StaticResource WrapperStyle}">
                <chartingToolkit:Chart Title="Inverse">
                    <chartingToolkit:Chart.Series>
                        <chartingToolkit:ScatterSeries
                          Title="Particulate Levels"
                          ItemsSource="{Binding LevelsInRainfall, Source={StaticResource ParticulateLevel}}"
                          IndependentValueBinding="{Binding Rainfall}"
                          DependentValueBinding="{Binding Particulate}" />
                        <samples:FunctionSeries
                          Function="110 + 1 / (x - 4)"
                          LineThickness="1">
                            <samples:FunctionSeries.Title>
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock Grid.Row="1" Text="f(x) = 110 + " VerticalAlignment="Center" />
                                    <StackPanel VerticalAlignment="Center">
                                        <TextBlock Text="1" HorizontalAlignment="Center" />
                                        <Line Stroke="Black" StrokeThickness="1" X1="0" X2="30" Y1="0" Y2="0" />
                                        <TextBlock Text="x - 4" HorizontalAlignment="Center" />
                                    </StackPanel>
                                </StackPanel>
                            </samples:FunctionSeries.Title>
                        </samples:FunctionSeries>
                    </chartingToolkit:Chart.Series>
                </chartingToolkit:Chart>
            </Grid>
            
            <Grid Style="{StaticResource WrapperStyle}">
                <chartingToolkit:Chart x:Name="CustomFunctionChart" Title="Custom Function">
                    <chartingToolkit:Chart.Series>
                        <chartingToolkit:ScatterSeries
                          Title="Particulate Levels"
                          ItemsSource="{Binding LevelsInRainfall, Source={StaticResource ParticulateLevel}}"
                          IndependentValueBinding="{Binding Rainfall}"
                          DependentValueBinding="{Binding Particulate}" />
                        <samples:FunctionSeries
                          Title="f(x) = 110 + 3 * Math.Sin(x)"
                          LineThickness="1" />
                    </chartingToolkit:Chart.Series>
                </chartingToolkit:Chart>
            </Grid>
        </toolkit:WrapPanel>
        
        <!-- Regression Scenario -->
        <ContentControl Content="Regression Scenario" Style="{StaticResource Header}"/>
        <Grid Height="500">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <TextBlock HorizontalAlignment="Right" Text="Regression: " />
            <ComboBox
              Grid.Column="1"
              SelectionChanged="OnRegressionTypeChanged"
              HorizontalAlignment="Left">
                <ComboBox.ItemsSource>
                    <toolkit:ObjectCollection>
                        <system:String>Linear</system:String>
                        <system:String>Quadratic</system:String>
                        <system:String>Cubic</system:String>
                        <system:String>Quartic</system:String>
                    </toolkit:ObjectCollection>
                </ComboBox.ItemsSource>
            </ComboBox>
            <chartingToolkit:Chart x:Name="ParticulateAnalysis" Grid.Row="1" Grid.ColumnSpan="2" Title="Particulate Level Analysis">
                <chartingToolkit:Chart.Series>
                    <chartingToolkit:ScatterSeries
                      Title="Particulate Levels"
                      ItemsSource="{Binding LevelsInRainfall, Source={StaticResource ParticulateLevel}}"
                      IndependentValueBinding="{Binding Rainfall}"
                      DependentValueBinding="{Binding Particulate}" />
                    <samples:FunctionSeries
                      Title="Regression"
                      LineBrush="Blue"
                      LineThickness="2" />
                </chartingToolkit:Chart.Series>
            </chartingToolkit:Chart>
        </Grid>
        
        <src:SourceViewer xmlns:src="clr-namespace:System.Windows.Controls.Samples;assembly=System.Windows.Controls.Samples.Common" xmlns:sys="clr-namespace:System;assembly=mscorlib">
  <src:SourceFile Path="CustomSeriesSample.xaml">
    <src:SourceFile.Source>
      <sys:String>&lt;!--
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
--&gt;
    
&lt;UserControl 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"

  xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
  xmlns:samples="clr-namespace:System.Windows.Controls.Samples"
  xmlns:system="clr-namespace:System;assembly=mscorlib"
  x:Class="System.Windows.Controls.Samples.CustomSeriesSample"&gt;
    &lt;StackPanel&gt;

        &lt;!-- Basic Examples --&gt;
        &lt;ContentControl Content="Basic Examples" Style="{StaticResource Header}"/&gt;
        &lt;toolkit:WrapPanel&gt;
            &lt;Grid Style="{StaticResource WrapperStyle}"&gt;
                &lt;chartingToolkit:Chart Title="Constant"&gt;
                    &lt;chartingToolkit:Chart.Series&gt;
                        &lt;chartingToolkit:ScatterSeries
                          Title="Particulate Levels"
                          ItemsSource="{Binding LevelsInRainfall, Source={StaticResource ParticulateLevel}}"
                          IndependentValueBinding="{Binding Rainfall}"
                          DependentValueBinding="{Binding Particulate}" /&gt;
                        &lt;samples:FunctionSeries
                          Function="110"
                          Title="f(x) = 110"
                          LineBrush="Blue"
                          LineThickness="2" /&gt;
                    &lt;/chartingToolkit:Chart.Series&gt;
                &lt;/chartingToolkit:Chart&gt;
            &lt;/Grid&gt;
            
            &lt;Grid Style="{StaticResource WrapperStyle}"&gt;
                &lt;chartingToolkit:Chart Title="Linear"&gt;
                    &lt;chartingToolkit:Chart.Series&gt;
                        &lt;chartingToolkit:ScatterSeries
                          Title="Particulate Levels"
                          ItemsSource="{Binding LevelsInRainfall, Source={StaticResource ParticulateLevel}}"
                          IndependentValueBinding="{Binding Rainfall}"
                          DependentValueBinding="{Binding Particulate}" /&gt;
                        &lt;samples:FunctionSeries
                          Function="110 + x"
                          Title="f(x) = 110 + x"
                          LineBrush="Green"
                          LineThickness="2" /&gt;
                    &lt;/chartingToolkit:Chart.Series&gt;
                &lt;/chartingToolkit:Chart&gt;
            &lt;/Grid&gt;
            
            &lt;Grid Style="{StaticResource WrapperStyle}"&gt;
                &lt;chartingToolkit:Chart Title="Quadratic"&gt;
                    &lt;chartingToolkit:Chart.Series&gt;
                        &lt;chartingToolkit:ScatterSeries
                          Title="Particulate Levels"
                          ItemsSource="{Binding LevelsInRainfall, Source={StaticResource ParticulateLevel}}"
                          IndependentValueBinding="{Binding Rainfall}"
                          DependentValueBinding="{Binding Particulate}" /&gt;
                        &lt;samples:FunctionSeries
                          Function="110 + (x - 4)^2"
                          LineBrush="Red"
                          LineThickness="1"&gt;
                            &lt;samples:FunctionSeries.Title&gt;
                                &lt;StackPanel Orientation="Horizontal"&gt;
                                    &lt;TextBlock Grid.Row="1" Text="f(x) = 110 + (x - 4)" Margin="0 4 0 0" /&gt;
                                    &lt;TextBlock Grid.Column="1" Text="2" FontSize="8" Margin="0"  /&gt;
                                &lt;/StackPanel&gt;
                            &lt;/samples:FunctionSeries.Title&gt;
                        &lt;/samples:FunctionSeries&gt;
                    &lt;/chartingToolkit:Chart.Series&gt;
                &lt;/chartingToolkit:Chart&gt;
            &lt;/Grid&gt;
            
            &lt;Grid Style="{StaticResource WrapperStyle}"&gt;
                &lt;chartingToolkit:Chart Title="Cubic"&gt;
                    &lt;chartingToolkit:Chart.Series&gt;
                        &lt;chartingToolkit:ScatterSeries
                          Title="Particulate Levels"
                          ItemsSource="{Binding LevelsInRainfall, Source={StaticResource ParticulateLevel}}"
                          IndependentValueBinding="{Binding Rainfall}"
                          DependentValueBinding="{Binding Particulate}" /&gt;
                        &lt;samples:FunctionSeries
                          Function="110 + (x - 4)^3"
                          LineBrush="Black"
                          LineThickness="3"&gt;
                            &lt;samples:FunctionSeries.Title&gt;
                                &lt;StackPanel Orientation="Horizontal"&gt;
                                    &lt;TextBlock Grid.Row="1" Text="f(x) = 110 + (x - 4)" Margin="0 4 0 0" /&gt;
                                    &lt;TextBlock Grid.Column="1" Text="3" FontSize="8" Margin="0"  /&gt;
                                &lt;/StackPanel&gt;
                            &lt;/samples:FunctionSeries.Title&gt;
                        &lt;/samples:FunctionSeries&gt;
                    &lt;/chartingToolkit:Chart.Series&gt;
                &lt;/chartingToolkit:Chart&gt;
            &lt;/Grid&gt;
            
            &lt;Grid Style="{StaticResource WrapperStyle}"&gt;
                &lt;chartingToolkit:Chart Title="Inverse"&gt;
                    &lt;chartingToolkit:Chart.Series&gt;
                        &lt;chartingToolkit:ScatterSeries
                          Title="Particulate Levels"
                          ItemsSource="{Binding LevelsInRainfall, Source={StaticResource ParticulateLevel}}"
                          IndependentValueBinding="{Binding Rainfall}"
                          DependentValueBinding="{Binding Particulate}" /&gt;
                        &lt;samples:FunctionSeries
                          Function="110 + 1 / (x - 4)"
                          LineThickness="1"&gt;
                            &lt;samples:FunctionSeries.Title&gt;
                                &lt;StackPanel Orientation="Horizontal"&gt;
                                    &lt;TextBlock Grid.Row="1" Text="f(x) = 110 + " VerticalAlignment="Center" /&gt;
                                    &lt;StackPanel VerticalAlignment="Center"&gt;
                                        &lt;TextBlock Text="1" HorizontalAlignment="Center" /&gt;
                                        &lt;Line Stroke="Black" StrokeThickness="1" X1="0" X2="30" Y1="0" Y2="0" /&gt;
                                        &lt;TextBlock Text="x - 4" HorizontalAlignment="Center" /&gt;
                                    &lt;/StackPanel&gt;
                                &lt;/StackPanel&gt;
                            &lt;/samples:FunctionSeries.Title&gt;
                        &lt;/samples:FunctionSeries&gt;
                    &lt;/chartingToolkit:Chart.Series&gt;
                &lt;/chartingToolkit:Chart&gt;
            &lt;/Grid&gt;
            
            &lt;Grid Style="{StaticResource WrapperStyle}"&gt;
                &lt;chartingToolkit:Chart x:Name="CustomFunctionChart" Title="Custom Function"&gt;
                    &lt;chartingToolkit:Chart.Series&gt;
                        &lt;chartingToolkit:ScatterSeries
                          Title="Particulate Levels"
                          ItemsSource="{Binding LevelsInRainfall, Source={StaticResource ParticulateLevel}}"
                          IndependentValueBinding="{Binding Rainfall}"
                          DependentValueBinding="{Binding Particulate}" /&gt;
                        &lt;samples:FunctionSeries
                          Title="f(x) = 110 + 3 * Math.Sin(x)"
                          LineThickness="1" /&gt;
                    &lt;/chartingToolkit:Chart.Series&gt;
                &lt;/chartingToolkit:Chart&gt;
            &lt;/Grid&gt;
        &lt;/toolkit:WrapPanel&gt;
        
        &lt;!-- Regression Scenario --&gt;
        &lt;ContentControl Content="Regression Scenario" Style="{StaticResource Header}"/&gt;
        &lt;Grid Height="500"&gt;
            &lt;Grid.RowDefinitions&gt;
                &lt;RowDefinition Height="Auto" /&gt;
                &lt;RowDefinition /&gt;
            &lt;/Grid.RowDefinitions&gt;
            &lt;Grid.ColumnDefinitions&gt;
                &lt;ColumnDefinition Width="Auto" /&gt;
                &lt;ColumnDefinition /&gt;
            &lt;/Grid.ColumnDefinitions&gt;
            &lt;TextBlock HorizontalAlignment="Right" Text="Regression: " /&gt;
            &lt;ComboBox
              Grid.Column="1"
              SelectionChanged="OnRegressionTypeChanged"
              HorizontalAlignment="Left"&gt;
                &lt;ComboBox.ItemsSource&gt;
                    &lt;toolkit:ObjectCollection&gt;
                        &lt;system:String&gt;Linear&lt;/system:String&gt;
                        &lt;system:String&gt;Quadratic&lt;/system:String&gt;
                        &lt;system:String&gt;Cubic&lt;/system:String&gt;
                        &lt;system:String&gt;Quartic&lt;/system:String&gt;
                    &lt;/toolkit:ObjectCollection&gt;
                &lt;/ComboBox.ItemsSource&gt;
            &lt;/ComboBox&gt;
            &lt;chartingToolkit:Chart x:Name="ParticulateAnalysis" Grid.Row="1" Grid.ColumnSpan="2" Title="Particulate Level Analysis"&gt;
                &lt;chartingToolkit:Chart.Series&gt;
                    &lt;chartingToolkit:ScatterSeries
                      Title="Particulate Levels"
                      ItemsSource="{Binding LevelsInRainfall, Source={StaticResource ParticulateLevel}}"
                      IndependentValueBinding="{Binding Rainfall}"
                      DependentValueBinding="{Binding Particulate}" /&gt;
                    &lt;samples:FunctionSeries
                      Title="Regression"
                      LineBrush="Blue"
                      LineThickness="2" /&gt;
                &lt;/chartingToolkit:Chart.Series&gt;
            &lt;/chartingToolkit:Chart&gt;
        &lt;/Grid&gt;
    &lt;/StackPanel&gt;
&lt;/UserControl&gt;
</sys:String>
    </src:SourceFile.Source>
  </src:SourceFile>
  <src:SourceFile Path="CustomSeriesSample.xaml.cs">
    <src:SourceFile.Source>
      <sys:String>// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Controls.DataVisualization.Charting;
using System.ComponentModel;

namespace System.Windows.Controls.Samples
{
    /// &lt;summary&gt;
    /// Charting sample demonstrating how to create a custom series.
    /// &lt;/summary&gt;
    [Sample("(2)Custom Series", DifficultyLevel.Advanced)]
    [Category("DataVisualization")]
    public partial class CustomSeriesSample : UserControl
    {
        /// &lt;summary&gt;
        /// Initializes a new instance of the CustomSeriesSample class.
        /// &lt;/summary&gt;
        public CustomSeriesSample()
        {
            InitializeComponent();

            // Use a custom function for a series
            FunctionSeries series = CustomFunctionChart.Series[1] as FunctionSeries;
            series.Function = x =&gt; 110 + 3 * Math.Sin(x);
        }

        /// &lt;summary&gt;
        /// Perform a regression against the particulate levels data.
        /// &lt;/summary&gt;
        /// &lt;param name="sender"&gt;The regression ComboBox.&lt;/param&gt;
        /// &lt;param name="e"&gt;Event arguments.&lt;/param&gt;
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called by an event handler in XAML.")]
        [SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Body", Justification = "Simplifies the sample.")]
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Simplifies the sample.")]
        private void OnRegressionTypeChanged(object sender, SelectionChangedEventArgs e)
        {
            // Get the options and the series
            ComboBox combo = sender as ComboBox;
            if (combo == null || ParticulateAnalysis == null)
            {
                return;
            }
            ScatterSeries dataSeries = ParticulateAnalysis.Series[0] as ScatterSeries;
            FunctionSeries regressionSeries = ParticulateAnalysis.Series[1] as FunctionSeries;
            if (dataSeries == null || regressionSeries == null)
            {
                return;
            }

            // Get the active DataPoints (this assumes the default template for
            // ScatterSeries)
            Canvas plotArea = VisualTreeHelper.GetChild(dataSeries, 0) as Canvas;
            if (plotArea == null)
            {
                return;
            }
            List&lt;DataPoint&gt; activePoints =
                plotArea
                .Children
                .OfType&lt;DataPoint&gt;()
                .ToList();

            // The dimensions were added linearly to the ComboBox
            int dimension = combo.SelectedIndex + 1;

            // Initialize a simple least squares analysis
            int i = 0;
            int j = 0;
            int k = 0;
            double[] y = new double[activePoints.Count];
            double[,] x = new double[activePoints.Count, dimension + 1];
            for (i = 0; i &lt; activePoints.Count; i++)
            {
                DataPoint point = activePoints[i];
                double independentValue = Convert.ToDouble(point.IndependentValue, CultureInfo.InvariantCulture);

                for (j = 0; j &lt;= dimension; j++)
                {
                    x[i, j] = Math.Pow(independentValue, j);
                }

                y[i] = Convert.ToDouble(point.DependentValue, CultureInfo.InvariantCulture);
            }

            // Create the equations
            double[][] matrix = new double[dimension + 1][];
            for (i = 0; i &lt;= dimension; i++)
            {
                // Create the row
                matrix[i] = new double[dimension + 2];

                // indeterminate coefficients
                for (j = 0; j &lt;= dimension; j++)
                {
                    matrix[i][j] = 0.0;
                    for (k = 0; k &lt; activePoints.Count; k++)
                    {
                        matrix[i][j] += x[k, i] * x[k, j];
                    }
                }

                // determinate values
                for (k = 0; k &lt; activePoints.Count; k++)
                {
                    matrix[i][dimension + 1] += x[k, i] * y[k];
                }
            }

            // Convert to row-echelon form
            i = 0;
            j = 0;
            while (i &lt;= dimension &amp;&amp; j &lt;= dimension)
            {
                // Get the pivot in column j starting at row i
                int pivotRow = i;
                for (k = i; k &lt;= dimension; k++)
                {
                    if (Math.Abs(matrix[k][j]) &gt; Math.Abs(matrix[pivotRow][j]))
                    {
                        pivotRow = k;
                    }
                }
                double pivot = matrix[pivotRow][j];

                // If we have a pivot element
                if (pivot != 0)
                {
                    // Swap the current row with the pivot row
                    double[] temp = matrix[i];
                    matrix[i] = matrix[pivotRow];
                    matrix[pivotRow] = temp;
                    pivotRow = i;

                    // Normalize the pivot row to the pivot
                    double c = matrix[i][j];
                    for (k = 0; k &lt;= dimension + 1; k++)
                    {
                        matrix[i][k] /= c;
                    }

                    // Clear out the pivot position from the remaining rows
                    for (k = i + 1; k &lt;= dimension; k++)
                    {
                        c = matrix[k][j];
                        for (int m = i; m &lt;= dimension + 1; m++)
                        {
                            matrix[k][m] -= c * matrix[i][m];
                        }
                    }

                    i++;
                }

                j++;
            }

            // Solve using substitution
            for (i = dimension - 1; i &gt;= 0; i--)
            {
                for (j = dimension; j &gt; i; j--)
                {
                    matrix[i][dimension + 1] -= matrix[i][j] * matrix[j][dimension + 1];
                    matrix[i][j] = 0;
                }
            }

            // Capture the coefficients
            double a0 = matrix[0][dimension + 1];
            double a1 = matrix[1][dimension + 1];
            double a2 = (dimension &gt;= 2) ? matrix[2][dimension + 1] : double.NaN;
            double a3 = (dimension &gt;= 3) ? matrix[3][dimension + 1] : double.NaN;
            double a4 = (dimension == 4) ? matrix[4][dimension + 1] : double.NaN;

            // Create the function
            Func&lt;double, double&gt; function = null;
            switch (dimension)
            {
                case 1:
                    function = z =&gt; a1 * z + a0;
                    break;
                case 2:
                    function = z =&gt; a2 * z * z + a1 * z + a0;
                    break;
                case 3:
                    function = z =&gt; a3 * z * z * z + a2 * z * z + a1 * z + a0;
                    break;
                case 4:
                    function = z =&gt; a4 * z * z * z * z + a3 * z * z * z + a2 * z * z + a1 * z + a0;
                    break;
            }

            // Create the title
            StackPanel title = new StackPanel { Orientation = Orientation.Horizontal };
            title.Children.Add(
                new TextBlock
                {
                    Text = "f(x) = ",
                    Margin = new Thickness(0, 4, 0, 0)
                });

            title.Children.Add(
                new TextBlock
                {
                    Text = a0.ToString("N3", CultureInfo.InvariantCulture),
                    Margin = new Thickness(0, 4, 0, 0)
                });
            AddTitleTerm(title, a1, 1);
            if (dimension &gt;= 2)
            {
                AddTitleTerm(title, a2, 2);
            }
            if (dimension &gt;= 3)
            {
                AddTitleTerm(title, a3, 3);
            }
            if (dimension == 4)
            {
                AddTitleTerm(title, a4, 4);
            }

            // Set the function and the title
            regressionSeries.Function = function;
            regressionSeries.Title = title;
        }

        /// &lt;summary&gt;
        /// Add a term to the title.
        /// &lt;/summary&gt;
        /// &lt;param name="title"&gt;The title container.&lt;/param&gt;
        /// &lt;param name="value"&gt;The value of the term.&lt;/param&gt;
        /// &lt;param name="exponent"&gt;The exponent of the term.&lt;/param&gt;
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called by a method called by an event handler in XAML.")]
        private static void AddTitleTerm(StackPanel title, double value, int exponent)
        {
            if (value == 0)
            {
                return;
            }

            title.Children.Add(
                new TextBlock
                {
                    Text = value &gt;= 0 ? " + " : " - ",
                    Margin = new Thickness(0, 4, 0, 0)
                });
            title.Children.Add(
                new TextBlock
                {
                    Text = string.Format(CultureInfo.InvariantCulture, "{0:N3}x", Math.Abs(value)),
                    Margin = new Thickness(0, 4, 0, 0)
                });

            if (exponent &gt; 1)
            {
                title.Children.Add(
                    new TextBlock
                    {
                        Text = exponent.ToString(CultureInfo.InvariantCulture),
                        FontSize = 8
                    });
            }
        }
    }
}</sys:String>
    </src:SourceFile.Source>
  </src:SourceFile>
  <src:SourceFile Path="CustomSeriesSample.xaml.vb">
    <src:SourceFile.Source>
      <sys:String>' (c) Copyright Microsoft Corporation.
' This source is subject to the Microsoft Public License (Ms-PL).
' Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
' All other rights reserved.

Imports Microsoft.VisualBasic
Imports System
Imports System.Collections.Generic
Imports System.Diagnostics.CodeAnalysis
Imports System.Globalization
Imports System.Linq
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Media
Imports System.Windows.Controls.DataVisualization.Charting
Imports System.ComponentModel

''' &lt;summary&gt;
''' Charting sample demonstrating how to create a custom series.
''' &lt;/summary&gt;
&lt;Sample("(2)Custom Series", DifficultyLevel.Advanced), Category("DataVisualization")&gt; _
Partial Public Class CustomSeriesSample
    Inherits UserControl
    ''' &lt;summary&gt;
    ''' Initializes a new instance of the CustomSeriesSample class.
    ''' &lt;/summary&gt;
    &lt;System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors", Justification:="InitializeComponent Required by Visual Studio.")&gt; _
    Public Sub New()
        InitializeComponent()

        ' Use a custom function for a series
        Dim series As FunctionSeries = TryCast(CustomFunctionChart.Series(1), FunctionSeries)
        series.Function = Function(x As Double) 110 + 3 * Math.Sin(x)
    End Sub

    ''' &lt;summary&gt;
    ''' Perform a regression against the particulate levels data.
    ''' &lt;/summary&gt;
    ''' &lt;param name="sender"&gt;The regression ComboBox.&lt;/param&gt;
    ''' &lt;param name="e"&gt;Event arguments.&lt;/param&gt;
    &lt;SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification:="Called by an event handler in XAML."), _
    SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId:="Body", Justification:="Simplifies the sample."), _
    SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification:="Simplifies the sample.")&gt; _
    Private Sub OnRegressionTypeChanged(ByVal sender As Object, ByVal e As SelectionChangedEventArgs)
        ' Get the options and the series
        Dim combo As ComboBox = TryCast(sender, ComboBox)
        If combo Is Nothing OrElse ParticulateAnalysis Is Nothing Then
            Return
        End If
        Dim dataSeries As ScatterSeries = TryCast(ParticulateAnalysis.Series(0), ScatterSeries)
        Dim regressionSeries As FunctionSeries = TryCast(ParticulateAnalysis.Series(1), FunctionSeries)
        If dataSeries Is Nothing OrElse regressionSeries Is Nothing Then
            Return
        End If

        ' Get the active DataPoints (this assumes the default template for
        ' ScatterSeries)
        Dim plotArea As Canvas = TryCast(VisualTreeHelper.GetChild(dataSeries, 0), Canvas)
        If plotArea Is Nothing Then
            Return
        End If
        Dim activePoints As List(Of DataPoint) = plotArea.Children.OfType(Of DataPoint)().ToList()

        ' The dimensions were added linearly to the ComboBox
        Dim dimension As Integer = combo.SelectedIndex + 1

        ' Initialize a simple least squares analysis
        Dim i As Integer = 0
        Dim j As Integer = 0
        Dim k As Integer = 0
        Dim y(activePoints.Count - 1) As Double
        Dim x(activePoints.Count - 1, dimension) As Double
        For i = 0 To activePoints.Count - 1
            Dim point As DataPoint = activePoints(i)
            Dim independentValue As Double = Convert.ToDouble(point.IndependentValue, CultureInfo.InvariantCulture)

            For j = 0 To dimension
                x(i, j) = Math.Pow(independentValue, j)
            Next j

            y(i) = Convert.ToDouble(point.DependentValue, CultureInfo.InvariantCulture)
        Next i

        ' Create the equations
        Dim matrix(dimension)() As Double
        For i = 0 To dimension
            ' Create the row
            matrix(i) = New Double(dimension + 2 - 1) {}

            ' indeterminate coefficients
            For j = 0 To dimension
                matrix(i)(j) = 0.0
                For k = 0 To activePoints.Count - 1
                    matrix(i)(j) += x(k, i) * x(k, j)
                Next k
            Next j

            ' determinate values
            For k = 0 To activePoints.Count - 1
                matrix(i)(dimension + 1) += x(k, i) * y(k)
            Next k
        Next i

        ' Convert to row-echelon form
        i = 0
        j = 0
        Do While i &lt;= dimension AndAlso j &lt;= dimension
            ' Get the pivot in column j starting at row i
            Dim pivotRow As Integer = i
            For k = i To dimension
                If Math.Abs(matrix(k)(j)) &gt; Math.Abs(matrix(pivotRow)(j)) Then
                    pivotRow = k
                End If
            Next k
            Dim pivot As Double = matrix(pivotRow)(j)

            ' If we have a pivot element
            If pivot &lt;&gt; 0 Then
                ' Swap the current row with the pivot row
                Dim temp() As Double = matrix(i)
                matrix(i) = matrix(pivotRow)
                matrix(pivotRow) = temp
                pivotRow = i

                ' Normalize the pivot row to the pivot
                Dim c As Double = matrix(i)(j)
                For k = 0 To dimension + 1
                    matrix(i)(k) /= c
                Next k

                ' Clear out the pivot position from the remaining rows
                For k = i + 1 To dimension
                    c = matrix(k)(j)
                    For m As Integer = i To dimension + 1
                        matrix(k)(m) -= c * matrix(i)(m)
                    Next m
                Next k

                i += 1
            End If

            j += 1
        Loop

        ' Solve using substitution
        For i = dimension - 1 To 0 Step -1
            For j = dimension To i + 1 Step -1
                matrix(i)(dimension + 1) -= matrix(i)(j) * matrix(j)(dimension + 1)
                matrix(i)(j) = 0
            Next j
        Next i

        ' Capture the coefficients
        Dim a0 As Double = matrix(0)(dimension + 1)
        Dim a1 As Double = matrix(1)(dimension + 1)
        Dim a2 As Double = If((dimension &gt;= 2), matrix(2)(dimension + 1), Double.NaN)
        Dim a3 As Double = If((dimension &gt;= 3), matrix(3)(dimension + 1), Double.NaN)
        Dim a4 As Double = If((dimension = 4), matrix(4)(dimension + 1), Double.NaN)

        ' Create the function
        Dim [function] As Func(Of Double, Double) = Nothing
        Select Case dimension
            Case 1
                [function] = Function(z) a1 * z + a0
            Case 2
                [function] = Function(z) a2 * z * z + a1 * z + a0
            Case 3
                [function] = Function(z) a3 * z * z * z + a2 * z * z + a1 * z + a0
            Case 4
                [function] = Function(z) a4 * z * z * z * z + a3 * z * z * z + a2 * z * z + a1 * z + a0
        End Select

        ' Create the title
        Dim title As StackPanel = New StackPanel With {.Orientation = Orientation.Horizontal}
        title.Children.Add(New TextBlock With _
                            { _
                                .Text = "f(x) = ", _
                                .Margin = New Thickness(0, 4, 0, 0) _
                            })

        title.Children.Add(New TextBlock With _
                            { _
                                .Text = a0.ToString("N3", CultureInfo.InvariantCulture), _
                                .Margin = New Thickness(0, 4, 0, 0) _
                            })
        AddTitleTerm(title, a1, 1)
        If dimension &gt;= 2 Then
            AddTitleTerm(title, a2, 2)
        End If
        If dimension &gt;= 3 Then
            AddTitleTerm(title, a3, 3)
        End If
        If dimension = 4 Then
            AddTitleTerm(title, a4, 4)
        End If

        ' Set the function and the title
        regressionSeries.Function = [function]
        regressionSeries.Title = title
    End Sub

    ''' &lt;summary&gt;
    ''' Add a term to the title.
    ''' &lt;/summary&gt;
    ''' &lt;param name="title"&gt;The title container.&lt;/param&gt;
    ''' &lt;param name="value"&gt;The value of the term.&lt;/param&gt;
    ''' &lt;param name="exponent"&gt;The exponent of the term.&lt;/param&gt;
    &lt;SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification:="Called by a method called by an event handler in XAML.")&gt; _
    Private Shared Sub AddTitleTerm(ByVal title As StackPanel, ByVal value As Double, ByVal exponent As Integer)
        If value = 0 Then
            Return
        End If

        title.Children.Add(New TextBlock With _
                            { _
                                .Text = If(value &gt;= 0, " + ", " - "), _
                                .Margin = New Thickness(0, 4, 0, 0) _
                            })
        title.Children.Add(New TextBlock With _
                            { _
                                .Text = String.Format(CultureInfo.InvariantCulture, "{0:N3}x", Math.Abs(value)), _
                                .Margin = New Thickness(0, 4, 0, 0) _
                            })

        If exponent &gt; 1 Then
            title.Children.Add(New TextBlock With _
                                { _
                                    .Text = exponent.ToString(CultureInfo.InvariantCulture), _
                                    .FontSize = 8 _
                                })
        End If
    End Sub
End Class
</sys:String>
    </src:SourceFile.Source>
  </src:SourceFile>
  <src:SourceFile Path="FunctionSeries.cs">
    <src:SourceFile.Source>
      <sys:String>// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Controls.DataVisualization;
using System.Windows.Controls.DataVisualization.Charting;

namespace System.Windows.Controls.Samples
{
    /// &lt;summary&gt;
    /// FunctionSeries is used to single variable functions on a chart.
    /// &lt;/summary&gt;
    [TemplatePart(Name = FunctionSeries.PlotAreaName, Type = typeof(Canvas))]
    public sealed partial class FunctionSeries : Series, IRangeProvider, IAxisListener
    {
        /// &lt;summary&gt;
        /// The default control template would normally reside in generic.xaml,
        /// but the sample project is an application and doesn't have that file.
        /// We're just putting it here, but a real control project wouldn't.
        /// &lt;/summary&gt;
        private const string DefaultTemplate =
@"&lt;ControlTemplate
  xmlns='http://schemas.microsoft.com/client/2007'
  xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  xmlns:samples='clr-namespace:System.Windows.Controls.Samples;assembly=System.Windows.Controls.Samples'
  TargetType='samples:FunctionSeries'&gt;
    &lt;Canvas x:Name='PlotArea'&gt;
        &lt;Path
          Stroke='{TemplateBinding LineBrush}'
          StrokeThickness='{TemplateBinding LineThickness}'
          Data='{TemplateBinding Geometry}' /&gt;
    &lt;/Canvas&gt;
&lt;/ControlTemplate&gt;";

        #region Template Parts
        /// &lt;summary&gt;
        /// Name of the plot area canvas.
        /// &lt;/summary&gt;
        private const string PlotAreaName = "PlotArea";

        /// &lt;summary&gt;
        /// Gets or sets the plot area canvas.
        /// &lt;/summary&gt;
        private Canvas PlotArea { get; set; }
        #endregion Template Parts

        #region public Func&lt;double, double&gt; Function
        /// &lt;summary&gt;
        /// Gets or sets the function to plot.
        /// &lt;/summary&gt;
        [TypeConverter(typeof(SimpleFunctionTypeConverter))]
        public Func&lt;double, double&gt; Function
        {
            get { return GetValue(FunctionProperty) as Func&lt;double, double&gt;; }
            set { SetValue(FunctionProperty, value); }
        }

        /// &lt;summary&gt;
        /// Identifies the Function dependency property.
        /// &lt;/summary&gt;
        public static readonly DependencyProperty FunctionProperty =
            DependencyProperty.Register(
                "Function",
                typeof(Func&lt;double, double&gt;),
                typeof(FunctionSeries),
                new PropertyMetadata(null, OnFunctionPropertyChanged));

        /// &lt;summary&gt;
        /// FunctionProperty property changed handler.
        /// &lt;/summary&gt;
        /// &lt;param name="d"&gt;FunctionSeries that changed its Function.&lt;/param&gt;
        /// &lt;param name="e"&gt;Event arguments.&lt;/param&gt;
        private static void OnFunctionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            FunctionSeries source = d as FunctionSeries;
            source.Refresh();
        }
        #endregion public Func&lt;double, double&gt; Function

        #region public Geometry Geometry
        /// &lt;summary&gt;
        /// Gets or sets the geometry of the line object rendering the function.
        /// &lt;/summary&gt;
        public Geometry Geometry
        {
            get { return GetValue(GeometryProperty) as Geometry; }
            set { SetValue(GeometryProperty, value); }
        }

        /// &lt;summary&gt;
        /// Identifies the Geometry dependency property.
        /// &lt;/summary&gt;
        public static readonly DependencyProperty GeometryProperty =
            DependencyProperty.Register(
                "Geometry",
                typeof(Geometry),
                typeof(FunctionSeries),
                new PropertyMetadata(null));
        #endregion public Geometry Geometry

        #region public Brush LineBrush
        /// &lt;summary&gt;
        /// Gets or sets the brush used to plot the function.
        /// &lt;/summary&gt;
        public Brush LineBrush
        {
            get { return GetValue(LineBrushProperty) as Brush; }
            set { SetValue(LineBrushProperty, value); }
        }

        /// &lt;summary&gt;
        /// Identifies the LineBrush dependency property.
        /// &lt;/summary&gt;
        public static readonly DependencyProperty LineBrushProperty =
            DependencyProperty.Register(
                "LineBrush",
                typeof(Brush),
                typeof(FunctionSeries),
                new PropertyMetadata(null, OnLineBrushPropertyChanged));

        /// &lt;summary&gt;
        /// LineBrushProperty property changed handler.
        /// &lt;/summary&gt;
        /// &lt;param name="d"&gt;FunctionSeries that changed its LineBrush.&lt;/param&gt;
        /// &lt;param name="e"&gt;Event arguments.&lt;/param&gt;
        private static void OnLineBrushPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            FunctionSeries source = d as FunctionSeries;
            Brush value = e.NewValue as Brush;
            source.LegendItem.DataContext = new ContentControl { Background = value };
        }
        #endregion public Brush LineBrush

        #region public double LineThickness
        /// &lt;summary&gt;
        /// Gets or sets the thickness of the line used to plot the function.
        /// &lt;/summary&gt;
        public double LineThickness
        {
            get { return (double) GetValue(LineThicknessProperty); }
            set { SetValue(LineThicknessProperty, value); }
        }

        /// &lt;summary&gt;
        /// Identifies the LineThickness dependency property.
        /// &lt;/summary&gt;
        public static readonly DependencyProperty LineThicknessProperty =
            DependencyProperty.Register(
                "LineThickness",
                typeof(double),
                typeof(FunctionSeries),
                new PropertyMetadata(1.0));
        #endregion public double LineThickness

        #region private IRangeAxis IndependentAxis
        /// &lt;summary&gt;
        /// Gets or sets the value of the independent axis.
        /// &lt;/summary&gt;
        private IRangeAxis IndependentAxis
        {
            get { return GetValue(IndependentAxisProperty) as IRangeAxis; }
            set { SetValue(IndependentAxisProperty, value); }
        }

        /// &lt;summary&gt;
        /// Identifies the IndependentAxis dependency property.
        /// &lt;/summary&gt;
        private static readonly DependencyProperty IndependentAxisProperty =
            DependencyProperty.Register(
                "IndependentAxis",
                typeof(IRangeAxis),
                typeof(FunctionSeries),
                null);
        #endregion protected IRangeAxis IndependentAxis

        #region private IRangeAxis DependentAxis
        /// &lt;summary&gt;
        /// Gets or sets the value of the dependent axis.
        /// &lt;/summary&gt;
        private IRangeAxis DependentAxis
        {
            get { return GetValue(DependentAxisProperty) as IRangeAxis; }
            set { SetValue(DependentAxisProperty, value); }
        }

        /// &lt;summary&gt;
        /// Identifies the DependentAxis dependency property.
        /// &lt;/summary&gt;
        private static readonly DependencyProperty DependentAxisProperty =
            DependencyProperty.Register(
                "DependentAxis",
                typeof(IRangeAxis),
                typeof(FunctionSeries),
                null);
        #endregion protected IRangeAxis DependentAxis

        /// &lt;summary&gt;
        /// Gets or sets the single chart legend item associated with the
        /// series.
        /// &lt;/summary&gt;
        private LegendItem LegendItem { get; set; }

        /// &lt;summary&gt;
        /// Gets or sets the Geometry used to clip the line to the PlotArea
        /// bounds.
        /// &lt;/summary&gt;
        private RectangleGeometry ClipGeometry { get; set; }

        /// &lt;summary&gt;
        /// Initializes a new instance of the FunctionSeries class.
        /// &lt;/summary&gt;
        public FunctionSeries()
        {
            LegendItem = new LegendItem();
            LegendItems.Add(LegendItem);
            Clip = ClipGeometry = new RectangleGeometry();
            SizeChanged += OnSizeChanged;

            // Explicitly load the default template since the samples project
            // is an application and does not have a generic.xaml file.
            Template = XamlReader.Load(DefaultTemplate) as ControlTemplate;
            LineBrush = new SolidColorBrush(Colors.Purple);
        }

        /// &lt;summary&gt;
        /// Refreshes data from data source and renders the series.
        /// &lt;/summary&gt;
        public override void Refresh()
        {
            if (SeriesHost == null || ActualWidth == 0)
            {
                return;
            }

            // Ensure we have a function to plot
            Func&lt;double, double&gt; function = Function;
            if (function == null)
            {
                return;
            }

            // Ensure we have axes
            IRangeAxis independent = GetAxis(AxisOrientation.X, IndependentAxis);
            IndependentAxis = independent;
            IRangeAxis dependent = GetAxis(AxisOrientation.Y, DependentAxis);
            DependentAxis = dependent;
            if (!independent.Range.HasData)
            {
                return;
            }

            // Create a geometry that matches the function to plot
            PathGeometry path = new PathGeometry();
            PathFigure figure = new PathFigure();

            // Get the range over which we will 
            double start = (double) independent.Range.Minimum;
            double end = (double) independent.Range.Maximum;

            // Adjust the line at each pixel
            double delta = (end - start) / ActualWidth;
            
            // We'll only add a new line segment when the slope is changing
            // between points
            Point last = GetPoint(start, function, independent, dependent);
            figure.StartPoint = last;
            double slope = double.NaN;
            for (double x = start + delta; x &lt;= end; x += delta)
            {
                Point next = GetPoint(x, function, independent, dependent);
                double newSlope = (next.Y - last.Y) / (next.X - last.X);

                if (slope != newSlope)
                {
                    figure.Segments.Add(new LineSegment { Point = last });
                }

                slope = newSlope;
                last = next;
            }
            figure.Segments.Add(new LineSegment { Point = last });

            path.Figures.Add(figure);
            Geometry = path;
        }

        /// &lt;summary&gt;
        /// Get a point in screen coordinates.
        /// &lt;/summary&gt;
        /// &lt;param name="x"&gt;Independent value.&lt;/param&gt;
        /// &lt;param name="function"&gt;The function.&lt;/param&gt;
        /// &lt;param name="independent"&gt;The independent axis.&lt;/param&gt;
        /// &lt;param name="dependent"&gt;The dependent axis.&lt;/param&gt;
        /// &lt;returns&gt;The point in screen coordinates.&lt;/returns&gt;
        private Point GetPoint(double x, Func&lt;double, double&gt; function, IRangeAxis independent, IRangeAxis dependent)
        {
            // Get the dependent value
            double y = double.NaN;
            try
            {
                y = function(x);
            }
            catch (DivideByZeroException)
            {
            }

            // Map the actual values into coordinate values
            return new Point(
                independent.GetPlotAreaCoordinate(x).Value.Value,
                Math.Min(
                    Math.Max(
                        ActualHeight - dependent.GetPlotAreaCoordinate(y).Value.Value,
                        -1),
                    ActualHeight + 1));
        }

        /// &lt;summary&gt;
        /// Get the plot area after loading it from XAML.
        /// &lt;/summary&gt;
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            PlotArea = GetTemplateChild("PlotArea") as Canvas;
        }

        /// &lt;summary&gt;
        /// Updates the visual appearance of all the data points when the size
        /// changes. 
        /// &lt;/summary&gt;
        /// &lt;param name="sender"&gt;The series.&lt;/param&gt;
        /// &lt;param name="e"&gt;Event arguments.&lt;/param&gt;
        private void OnSizeChanged(object sender, SizeChangedEventArgs e)
        {
            // Update the clip geometry
            ClipGeometry.Rect = new Rect(0.0, 0.0, e.NewSize.Width, e.NewSize.Height);

            // Update the PlotArea size and refresh.
            if (PlotArea != null)
            {
                PlotArea.Width = e.NewSize.Width;
                PlotArea.Height = e.NewSize.Height;
                Refresh();
            }
        }

        /// &lt;summary&gt;
        /// Sets all the text the legend items to the title.
        /// &lt;/summary&gt;
        /// &lt;param name="oldValue"&gt;The old title.&lt;/param&gt;
        /// &lt;param name="newValue"&gt;The new title.&lt;/param&gt;
        protected override void OnTitleChanged(object oldValue, object newValue)
        {
            base.OnTitleChanged(oldValue, newValue);
            LegendItem.Content = Title;
        }

        /// &lt;summary&gt;
        /// Get or create a linear numeric axis in the correct dimension.
        /// &lt;/summary&gt;
        /// &lt;param name="orientation"&gt;Dimension of the axis to create.&lt;/param&gt;
        /// &lt;param name="oldAxis"&gt;
        /// Old value of the axis in this dimension.
        /// &lt;/param&gt;
        /// &lt;returns&gt;New value of the axis in this dimension.&lt;/returns&gt;
        private IRangeAxis GetAxis(AxisOrientation orientation, IRangeAxis oldAxis)
        {
            // Check the existing axes for a potential axis
            IRangeAxis axis =
                (from IRangeAxis a in SeriesHost.Axes.OfType&lt;IRangeAxis&gt;()
                 where a.Orientation == orientation
                 select a)
                .FirstOrDefault();

            if (axis == null)
            {
                // Create a new axis if not found
                axis = new LinearAxis
                {
                    Orientation = orientation,
                };
            }

            if (oldAxis != axis)
            {
                // Unregister any existing axis
                if (oldAxis != null)
                {
                    oldAxis.RegisteredListeners.Remove(this);
                }
                
                // Register the new axis
                if (!axis.RegisteredListeners.Contains(this))
                {
                    axis.RegisteredListeners.Add(this);
                }
            }

            return axis;
        }

        /// &lt;summary&gt;
        /// Updates the series when the axis is invalidated.
        /// &lt;/summary&gt;
        /// &lt;param name="axis"&gt;The axis that was invalidated.&lt;/param&gt;
        public void AxisInvalidated(IAxis axis)
        {
            if (DependentAxis != null &amp;&amp; IndependentAxis != null)
            {
                Refresh();
            }
        }

        /// &lt;summary&gt;
        /// Ensures that chart and series are kept in a consistent state when a
        /// series is added or removed from a chart. 
        /// &lt;/summary&gt;
        /// &lt;param name="oldValue"&gt;Old chart.&lt;/param&gt;
        /// &lt;param name="newValue"&gt;New chart.&lt;/param&gt;
        protected override void OnSeriesHostPropertyChanged(ISeriesHost oldValue, ISeriesHost newValue)
        {
            IRangeAxis axis = null;

            // Unregister the axes from the old chart
            if (oldValue != null)
            {
                axis = IndependentAxis;
                if (axis != null)
                {
                    axis.RegisteredListeners.Remove(this);
                    IndependentAxis = null;
                }

                axis = DependentAxis;
                if (axis != null)
                {
                    axis.RegisteredListeners.Remove(this);
                    DependentAxis = null;
                }
            }

            // Register the axes with new chart
            if (newValue != null)
            {
                axis = IndependentAxis;
                if (axis != null)
                {
                    axis.RegisteredListeners.Add(this);
                }

                axis = DependentAxis;
                if (axis != null)
                {
                    axis.RegisteredListeners.Add(this);
                }
            }

            base.OnSeriesHostPropertyChanged(oldValue, newValue);
        }

        /// &lt;summary&gt;
        /// If data is found returns the minimum and maximum dependent numeric
        /// values. 
        /// &lt;/summary&gt;
        /// &lt;param name="rangeConsumer"&gt;IRangeConsumer that needs the data.&lt;/param&gt;
        /// &lt;returns&gt;
        /// The range of values or empty if no data is present.
        /// &lt;/returns&gt;
        public Range&lt;IComparable&gt; GetRange(IRangeConsumer rangeConsumer)
        {
            // Use an empty range so we only plot over the area used by other
            // axes.
            return new Range&lt;IComparable&gt;();
        }
    }
}
</sys:String>
    </src:SourceFile.Source>
  </src:SourceFile>
  <src:SourceFile Path="FunctionSeries.vb">
    <src:SourceFile.Source>
      <sys:String>' (c) Copyright Microsoft Corporation.
' This source is subject to the Microsoft Public License (Ms-PL).
' Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
' All other rights reserved.

Imports Microsoft.VisualBasic
Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Diagnostics.CodeAnalysis
Imports System.Linq
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Markup
Imports System.Windows.Media
Imports System.Windows.Controls.DataVisualization
Imports System.Windows.Controls.DataVisualization.Charting

''' &lt;summary&gt;
''' FunctionSeries is used to single variable functions on a chart.
''' &lt;/summary&gt;
&lt;TemplatePart(Name:=FunctionSeries.PlotAreaName, Type:=GetType(Canvas))&gt; _
Partial Public NotInheritable Class FunctionSeries
    Inherits Series
    Implements IRangeProvider, IAxisListener
    ''' &lt;summary&gt;
    ''' The default control template would normally reside in generic.xaml,
    ''' but the sample project is an application and doesn't have that file.
    ''' We're just putting it here, but a real control project wouldn't.
    ''' &lt;/summary&gt;
    Private Const DefaultTemplate As String = "&lt;ControlTemplate" &amp; ControlChars.CrLf &amp; _
    "  xmlns='http://schemas.microsoft.com/client/2007'" &amp; ControlChars.CrLf &amp; _
    "  xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'" &amp; ControlChars.CrLf &amp; _
    "  xmlns:samples='clr-namespace:System.Windows.Controls.Samples;assembly=System.Windows.Controls.Samples'" &amp; ControlChars.CrLf &amp; _
    "  TargetType='samples:FunctionSeries'&gt;" &amp; ControlChars.CrLf &amp; _
    "    &lt;Canvas x:Name='PlotArea'&gt;" &amp; ControlChars.CrLf &amp; _
    "        &lt;Path" &amp; ControlChars.CrLf &amp; _
    "          Stroke='{TemplateBinding LineBrush}'" &amp; ControlChars.CrLf &amp; _
    "          StrokeThickness='{TemplateBinding LineThickness}'" &amp; ControlChars.CrLf &amp; _
    "          Data='{TemplateBinding Geometry}' /&gt;" &amp; ControlChars.CrLf &amp; _
    "    &lt;/Canvas&gt;" &amp; ControlChars.CrLf &amp; _
    "&lt;/ControlTemplate&gt;"

#Region "Template Parts"
    ''' &lt;summary&gt;
    ''' Name of the plot area canvas.
    ''' &lt;/summary&gt;
    Public Const PlotAreaName As String = "PlotArea"

    ''' &lt;summary&gt;
    ''' Gets or sets the plot area canvas.
    ''' &lt;/summary&gt;
    Private privatePlotArea As Canvas
    Private Property PlotArea() As Canvas
        Get
            Return privatePlotArea
        End Get
        Set(ByVal value As Canvas)
            privatePlotArea = value
        End Set
    End Property
#End Region ' Template Parts

#Region "public Func&lt;double, double&gt; Function"
    ''' &lt;summary&gt;
    ''' Gets or sets the function to plot.
    ''' &lt;/summary&gt;
    &lt;TypeConverter(GetType(SimpleFunctionTypeConverter))&gt; _
    Public Property [Function]() As Func(Of Double, Double)
        Get
            Return TryCast(GetValue(FunctionProperty), Func(Of Double, Double))
        End Get
        Set(ByVal value As Func(Of Double, Double))
            SetValue(FunctionProperty, value)
        End Set
    End Property

    ''' &lt;summary&gt;
    ''' Identifies the Function dependency property.
    ''' &lt;/summary&gt;
    Public Shared ReadOnly FunctionProperty As DependencyProperty = _
        DependencyProperty.Register( _
            "Function", _
            GetType(Func(Of Double, Double)), _
            GetType(FunctionSeries), _
            New PropertyMetadata(Nothing, AddressOf OnFunctionPropertyChanged))

    ''' &lt;summary&gt;
    ''' FunctionProperty property changed handler.
    ''' &lt;/summary&gt;
    ''' &lt;param name="d"&gt;FunctionSeries that changed its Function.&lt;/param&gt;
    ''' &lt;param name="e"&gt;Event arguments.&lt;/param&gt;
    Private Shared Sub OnFunctionPropertyChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
        Dim source As FunctionSeries = TryCast(d, FunctionSeries)
        source.Refresh()
    End Sub
#End Region ' public Func&lt;double, double&gt; Function

#Region "public Geometry Geometry"
    ''' &lt;summary&gt;
    ''' Gets or sets the geometry of the line object rendering the function.
    ''' &lt;/summary&gt;
    Public Property Geometry() As Geometry
        Get
            Return TryCast(GetValue(GeometryProperty), Geometry)
        End Get
        Set(ByVal value As Geometry)
            SetValue(GeometryProperty, value)
        End Set
    End Property

    ''' &lt;summary&gt;
    ''' Identifies the Geometry dependency property.
    ''' &lt;/summary&gt;
    Public Shared ReadOnly GeometryProperty As DependencyProperty = _
        DependencyProperty.Register( _
            "Geometry", _
            GetType(Geometry), _
            GetType(FunctionSeries), _
            New PropertyMetadata(Nothing))
#End Region ' public Geometry Geometry

#Region "public Brush LineBrush"
    ''' &lt;summary&gt;
    ''' Gets or sets the brush used to plot the function.
    ''' &lt;/summary&gt;
    Public Property LineBrush() As Brush
        Get
            Return TryCast(GetValue(LineBrushProperty), Brush)
        End Get
        Set(ByVal value As Brush)
            SetValue(LineBrushProperty, value)
        End Set
    End Property

    ''' &lt;summary&gt;
    ''' Identifies the LineBrush dependency property.
    ''' &lt;/summary&gt;
    Public Shared ReadOnly LineBrushProperty As DependencyProperty = _
        DependencyProperty.Register( _
            "LineBrush", _
            GetType(Brush), _
            GetType(FunctionSeries), _
            New PropertyMetadata(Nothing, AddressOf OnLineBrushPropertyChanged))

    ''' &lt;summary&gt;
    ''' LineBrushProperty property changed handler.
    ''' &lt;/summary&gt;
    ''' &lt;param name="d"&gt;FunctionSeries that changed its LineBrush.&lt;/param&gt;
    ''' &lt;param name="e"&gt;Event arguments.&lt;/param&gt;
    Private Shared Sub OnLineBrushPropertyChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
        Dim source As FunctionSeries = TryCast(d, FunctionSeries)
        Dim value As Brush = TryCast(e.NewValue, Brush)
        source.LegendItem.DataContext = New ContentControl With {.Background = value}
    End Sub
#End Region ' public Brush LineBrush

#Region "public double LineThickness"
    ''' &lt;summary&gt;
    ''' Gets or sets the thickness of the line used to plot the function.
    ''' &lt;/summary&gt;
    Public Property LineThickness() As Double
        Get
            Return CDbl(GetValue(LineThicknessProperty))
        End Get
        Set(ByVal value As Double)
            SetValue(LineThicknessProperty, value)
        End Set
    End Property

    ''' &lt;summary&gt;
    ''' Identifies the LineThickness dependency property.
    ''' &lt;/summary&gt;
    Public Shared ReadOnly LineThicknessProperty As DependencyProperty = _
        DependencyProperty.Register( _
            "LineThickness", _
            GetType(Double), _
            GetType(FunctionSeries), _
            New PropertyMetadata(1.0))
#End Region ' public double LineThickness

#Region "private IRangeAxis IndependentAxis"
    ''' &lt;summary&gt;
    ''' Gets or sets the value of the independent axis.
    ''' &lt;/summary&gt;
    Private Property IndependentAxis() As IRangeAxis
        Get
            Return TryCast(GetValue(IndependentAxisProperty), IRangeAxis)
        End Get
        Set(ByVal value As IRangeAxis)
            SetValue(IndependentAxisProperty, value)
        End Set
    End Property

    ''' &lt;summary&gt;
    ''' Identifies the IndependentAxis dependency property.
    ''' &lt;/summary&gt;
    Private Shared ReadOnly IndependentAxisProperty As DependencyProperty = _
        DependencyProperty.Register( _
            "IndependentAxis", _
            GetType(IRangeAxis), _
            GetType(FunctionSeries), _
            Nothing)
#End Region ' protected IRangeAxis IndependentAxis

#Region "private IRangeAxis DependentAxis"
    ''' &lt;summary&gt;
    ''' Gets or sets the value of the dependent axis.
    ''' &lt;/summary&gt;
    Private Property DependentAxis() As IRangeAxis
        Get
            Return TryCast(GetValue(DependentAxisProperty), IRangeAxis)
        End Get
        Set(ByVal value As IRangeAxis)
            SetValue(DependentAxisProperty, value)
        End Set
    End Property

    ''' &lt;summary&gt;
    ''' Identifies the DependentAxis dependency property.
    ''' &lt;/summary&gt;
    Private Shared ReadOnly DependentAxisProperty As DependencyProperty = _
        DependencyProperty.Register( _
            "DependentAxis", _
            GetType(IRangeAxis), _
            GetType(FunctionSeries), _
            Nothing)
#End Region ' protected IRangeAxis DependentAxis

    ''' &lt;summary&gt;
    ''' Gets or sets the single chart legend item associated with the
    ''' series.
    ''' &lt;/summary&gt;
    Private privateLegendItem As LegendItem
    Private Property LegendItem() As LegendItem
        Get
            Return privateLegendItem
        End Get
        Set(ByVal value As LegendItem)
            privateLegendItem = value
        End Set
    End Property

    ''' &lt;summary&gt;
    ''' Gets or sets the Geometry used to clip the line to the PlotArea
    ''' bounds.
    ''' &lt;/summary&gt;
    Private privateClipGeometry As RectangleGeometry
    Private Property ClipGeometry() As RectangleGeometry
        Get
            Return privateClipGeometry
        End Get
        Set(ByVal value As RectangleGeometry)
            privateClipGeometry = value
        End Set
    End Property

    ''' &lt;summary&gt;
    ''' Initializes a new instance of the FunctionSeries class.
    ''' &lt;/summary&gt;
    Public Sub New()
        LegendItem = New LegendItem()
        LegendItems.Add(LegendItem)
        ClipGeometry = New RectangleGeometry()
        Clip = ClipGeometry

        ' Explicitly load the default template since the samples project
        ' is an application and does not have a generic.xaml file.
        Template = TryCast(XamlReader.Load(DefaultTemplate), ControlTemplate)
        LineBrush = New SolidColorBrush(Colors.Purple)
    End Sub

    ''' &lt;summary&gt;
    ''' Refreshes data from data source and renders the series.
    ''' &lt;/summary&gt;
    Public Overrides Sub Refresh()
        If SeriesHost Is Nothing OrElse ActualWidth = 0 Then
            Return
        End If

        ' Ensure we have a function to plot
        Dim [function] As Func(Of Double, Double) = Me.Function
        If [function] Is Nothing Then
            Return
        End If

        ' Ensure we have axes
        Dim independent As IRangeAxis = GetAxis(AxisOrientation.X, IndependentAxis)
        IndependentAxis = independent
        Dim dependent As IRangeAxis = GetAxis(AxisOrientation.Y, DependentAxis)
        DependentAxis = dependent
        If (Not independent.Range.HasData) Then
            Return
        End If

        ' Create a geometry that matches the function to plot
        Dim path As New PathGeometry()
        Dim figure As New PathFigure()

        ' Get the range over which we will 
        Dim start As Double = CDbl(independent.Range.Minimum)
        Dim [end] As Double = CDbl(independent.Range.Maximum)

        ' Adjust the line at each pixel
        Dim delta As Double = ([end] - start) / ActualWidth

        ' We'll only add a new line segment when the slope is changing
        ' between points
        Dim last As Point = GetPoint(start, [function], independent, dependent)
        figure.StartPoint = last
        Dim slope As Double = Double.NaN
        For x As Double = start + delta To [end] Step delta
            Dim [next] As Point = GetPoint(x, [function], independent, dependent)
            Dim newSlope As Double = ([next].Y - last.Y) / ([next].X - last.X)

            If slope &lt;&gt; newSlope Then
                figure.Segments.Add(New LineSegment With {.Point = last})
            End If

            slope = newSlope
            last = [next]
        Next x
        figure.Segments.Add(New LineSegment With {.Point = last})

        path.Figures.Add(figure)
        Geometry = path
    End Sub

    ''' &lt;summary&gt;
    ''' Get a point in screen coordinates.
    ''' &lt;/summary&gt;
    ''' &lt;param name="x"&gt;Independent value.&lt;/param&gt;
    ''' &lt;param name="function"&gt;The function.&lt;/param&gt;
    ''' &lt;param name="independent"&gt;The independent axis.&lt;/param&gt;
    ''' &lt;param name="dependent"&gt;The dependent axis.&lt;/param&gt;
    ''' &lt;returns&gt;The point in screen coordinates.&lt;/returns&gt;
    Private Function GetPoint(ByVal x As Double, ByVal [function] As Func(Of Double, Double), ByVal independent As IRangeAxis, ByVal dependent As IRangeAxis) As Point
        ' Get the dependent value
        Dim y As Double = Double.NaN
        Try
            y = [function](x)
        Catch e1 As DivideByZeroException
        End Try

        ' Map the actual values into coordinate values
        Return New Point( _
            independent.GetPlotAreaCoordinate(x).Value.Value, _
            Math.Min( _
                Math.Max( _
                    ActualHeight - dependent.GetPlotAreaCoordinate(y).Value.Value, _
                    -1), _
                ActualHeight + 1))
    End Function

    ''' &lt;summary&gt;
    ''' Get the plot area after loading it from XAML.
    ''' &lt;/summary&gt;
    Public Overrides Sub OnApplyTemplate()
        MyBase.OnApplyTemplate()
        PlotArea = TryCast(GetTemplateChild("PlotArea"), Canvas)
    End Sub

    ''' &lt;summary&gt;
    ''' Updates the visual appearance of all the data points when the size
    ''' changes. 
    ''' &lt;/summary&gt;
    ''' &lt;param name="sender"&gt;The series.&lt;/param&gt;
    ''' &lt;param name="e"&gt;Event arguments.&lt;/param&gt;
    Private Sub OnSizeChanged(ByVal sender As Object, ByVal e As SizeChangedEventArgs) Handles Me.SizeChanged
        ' Update the clip geometry
        ClipGeometry.Rect = New Rect(0.0, 0.0, e.NewSize.Width, e.NewSize.Height)

        ' Update the PlotArea size and refresh.
        If PlotArea IsNot Nothing Then
            PlotArea.Width = e.NewSize.Width
            PlotArea.Height = e.NewSize.Height
            Refresh()
        End If
    End Sub

    ''' &lt;summary&gt;
    ''' Sets all the text the legend items to the title.
    ''' &lt;/summary&gt;
    ''' &lt;param name="oldValue"&gt;The old title.&lt;/param&gt;
    ''' &lt;param name="newValue"&gt;The new title.&lt;/param&gt;
    Protected Overrides Sub OnTitleChanged(ByVal oldValue As Object, ByVal newValue As Object)
        MyBase.OnTitleChanged(oldValue, newValue)
        LegendItem.Content = Title
    End Sub

    ''' &lt;summary&gt;
    ''' Get or create a linear numeric axis in the correct dimension.
    ''' &lt;/summary&gt;
    ''' &lt;param name="orientation"&gt;Dimension of the axis to create.&lt;/param&gt;
    ''' &lt;param name="oldAxis"&gt;
    ''' Old value of the axis in this dimension.
    ''' &lt;/param&gt;
    ''' &lt;returns&gt;New value of the axis in this dimension.&lt;/returns&gt;
    Private Function GetAxis(ByVal orientation As AxisOrientation, ByVal oldAxis As IRangeAxis) As IRangeAxis
        ' Check the existing axes for a potential axis
        Dim axis As IRangeAxis = ( _
          From a As IRangeAxis In SeriesHost.Axes.OfType(Of IRangeAxis)() _
          Where a.Orientation = orientation _
          Select a).FirstOrDefault()

        If axis Is Nothing Then
            ' Create a new axis if not found
            axis = New LinearAxis With {.Orientation = orientation}
        End If

        If oldAxis IsNot axis Then
            ' Unregister any existing axis
            If oldAxis IsNot Nothing Then
                oldAxis.RegisteredListeners.Remove(Me)
            End If

            ' Register the new axis
            If (Not axis.RegisteredListeners.Contains(Me)) Then
                axis.RegisteredListeners.Add(Me)
            End If
        End If

        Return axis
    End Function

    ''' &lt;summary&gt;
    ''' Updates the series when the axis is invalidated.
    ''' &lt;/summary&gt;
    ''' &lt;param name="axis"&gt;The axis that was invalidated.&lt;/param&gt;
    Public Sub AxisInvalidated(ByVal axis As IAxis) Implements IAxisListener.AxisInvalidated
        If DependentAxis IsNot Nothing AndAlso IndependentAxis IsNot Nothing Then
            Refresh()
        End If
    End Sub

    ''' &lt;summary&gt;
    ''' Ensures that chart and series are kept in a consistent state when a
    ''' series is added or removed from a chart. 
    ''' &lt;/summary&gt;
    ''' &lt;param name="oldValue"&gt;Old chart.&lt;/param&gt;
    ''' &lt;param name="newValue"&gt;New chart.&lt;/param&gt;
    Protected Overrides Sub OnSeriesHostPropertyChanged(ByVal oldValue As ISeriesHost, ByVal newValue As ISeriesHost)
        Dim axis As IRangeAxis = Nothing

        ' Unregister the axes from the old chart
        If oldValue IsNot Nothing Then
            axis = IndependentAxis
            If axis IsNot Nothing Then
                axis.RegisteredListeners.Remove(Me)
                IndependentAxis = Nothing
            End If

            axis = DependentAxis
            If axis IsNot Nothing Then
                axis.RegisteredListeners.Remove(Me)
                DependentAxis = Nothing
            End If
        End If

        ' Register the axes with new chart
        If newValue IsNot Nothing Then
            axis = IndependentAxis
            If axis IsNot Nothing Then
                axis.RegisteredListeners.Add(Me)
            End If

            axis = DependentAxis
            If axis IsNot Nothing Then
                axis.RegisteredListeners.Add(Me)
            End If
        End If

        MyBase.OnSeriesHostPropertyChanged(oldValue, newValue)
    End Sub

    ''' &lt;summary&gt;
    ''' If data is found returns the minimum and maximum dependent numeric
    ''' values. 
    ''' &lt;/summary&gt;
    ''' &lt;param name="rangeConsumer"&gt;IRangeConsumer that needs the data.&lt;/param&gt;
    ''' &lt;returns&gt;
    ''' The range of values or empty if no data is present.
    ''' &lt;/returns&gt;
    Public Function GetRange(ByVal rangeConsumer As IRangeConsumer) As Range(Of IComparable) Implements IRangeProvider.GetRange
        ' Use an empty range so we only plot over the area used by other
        ' axes.
        Return New Range(Of IComparable)()
    End Function
End Class
</sys:String>
    </src:SourceFile.Source>
  </src:SourceFile>
  <src:SourceFile Path="SimpleFunctionTypeConverter.cs">
    <src:SourceFile.Source>
      <sys:String>// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using Sle = System.Linq.Expressions;
using System.Text;

namespace System.Windows.Controls.Samples
{
    /// &lt;summary&gt;
    /// TypeConverter used for creating single variable functions from simple
    /// arithmetic expressions.
    /// &lt;/summary&gt;
    public class SimpleFunctionTypeConverter : TypeConverter
    {
        /// &lt;summary&gt;
        /// Initializes a new instance of the SimpleFunctionTypeConverter class.
        /// &lt;/summary&gt;
        public SimpleFunctionTypeConverter()
        {
        }

        /// &lt;summary&gt;
        /// Determine whether the sourceType can be converted to a single
        /// variable function.
        /// &lt;/summary&gt;
        /// &lt;param name="context"&gt;Conversion context.&lt;/param&gt;
        /// &lt;param name="sourceType"&gt;The type to convert from.&lt;/param&gt;
        /// &lt;returns&gt;
        /// A value indicating whether the type can be converted.
        /// &lt;/returns&gt;
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof(string);
        }

        /// &lt;summary&gt;
        /// Convert the value into a single variable function.
        /// &lt;/summary&gt;
        /// &lt;param name="context"&gt;Conversion context.&lt;/param&gt;
        /// &lt;param name="culture"&gt;Conversion culture.&lt;/param&gt;
        /// &lt;param name="value"&gt;The value to convert.&lt;/param&gt;
        /// &lt;returns&gt;A single variable function.&lt;/returns&gt;
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            Func&lt;double, double&gt; function = null;

            string text = value as string;
            if (!string.IsNullOrEmpty(text))
            {
                function = new Parser(text).Function;
            }

            return function;
        }

        /// &lt;summary&gt;
        /// Defines the type of a token.
        /// &lt;/summary&gt;
        private enum TokenType
        {
            /// &lt;summary&gt;
            /// A numeric value..
            /// &lt;/summary&gt;
            Number,

            /// &lt;summary&gt;
            /// An identifier.
            /// &lt;/summary&gt;
            Identifier,

            /// &lt;summary&gt;
            /// The addition operator.
            /// &lt;/summary&gt;
            Addition,

            /// &lt;summary&gt;
            /// The substraction operator.
            /// &lt;/summary&gt;
            Subtraction,

            /// &lt;summary&gt;
            /// The exponentiation operator.
            /// &lt;/summary&gt;
            Multiplication,

            /// &lt;summary&gt;
            /// The division operator.
            /// &lt;/summary&gt;
            Division,

            /// &lt;summary&gt;
            /// The exponentiation operator.
            /// &lt;/summary&gt;
            Exponentiation,

            /// &lt;summary&gt;
            /// A left parenthesis.
            /// &lt;/summary&gt;
            LeftParenthesis,

            /// &lt;summary&gt;
            /// A right parenthesis.
            /// &lt;/summary&gt;
            RightParenthesis
        }

        /// &lt;summary&gt;
        /// Represents a lexical token.
        /// &lt;/summary&gt;
        private class Token
        {
            /// &lt;summary&gt;
            /// Gets or sets the type of the token.
            /// &lt;/summary&gt;
            public TokenType TokenType { get; set; }

            /// &lt;summary&gt;
            /// Gets or sets the value of a token (for numbers and identifiers).
            /// &lt;/summary&gt;
            public object Value { get; set; }

            /// &lt;summary&gt;
            /// Initializes a new instance of the Token class.
            /// &lt;/summary&gt;
            public Token()
            {
            }
        }

        /// &lt;summary&gt;
        /// Perform lexical analysis of simple expressions.
        /// &lt;/summary&gt;
        private class Lexer
        {
            /// &lt;summary&gt;
            /// Gets or sets the input string to scan.
            /// &lt;/summary&gt;
            internal string Input { get; set; }

            /// &lt;summary&gt;
            /// Gets or sets the current position of the lexer.
            /// &lt;/summary&gt;
            internal int Position { get; set; }

            /// &lt;summary&gt;
            /// Gets a value indicating whether the lexer has room to advance
            /// through the input.
            /// &lt;/summary&gt;
            internal bool CanAdvance
            {
                get { return Position &lt; Input.Length; }
            }

            /// &lt;summary&gt;
            /// Gets the character at the current input position.
            /// &lt;/summary&gt;
            private char Current
            {
                get { return Input[Position]; }
            }

            /// &lt;summary&gt;
            /// Gets or sets the lookahead token.
            /// &lt;/summary&gt;
            private Token Lookahead { get; set; }

            /// &lt;summary&gt;
            /// Initializes a new instance of the Lexer class.
            /// &lt;/summary&gt;
            /// &lt;param name="input"&gt;The input to analyze.&lt;/param&gt;
            public Lexer(string input)
            {
                Debug.Assert(!string.IsNullOrEmpty(input), "input shuould not be null or empty!");
                Input = input;
            }

            /// &lt;summary&gt;
            /// Advance the token to the next input.
            /// &lt;/summary&gt;
            /// &lt;returns&gt;The token that was read.&lt;/returns&gt;
            private Token ReadNext()
            {
                // Eat as much whitespace as possible
                while (CanAdvance &amp;&amp; char.IsWhiteSpace(Current))
                {
                    Position++;
                }

                // Match a literal token
                Token token =
                    MatchLiteral('(', TokenType.LeftParenthesis) ??
                    MatchLiteral(')', TokenType.RightParenthesis) ??
                    MatchLiteral('+', TokenType.Addition) ??
                    MatchLiteral('-', TokenType.Subtraction) ??
                    MatchLiteral('*', TokenType.Multiplication) ??
                    MatchLiteral('/', TokenType.Division) ??
                    MatchLiteral('^', TokenType.Exponentiation);

                // Match identifier or number tokens
                if (token == null)
                {
                    int start = Position;
                    
                    // Try and match identifiers
                    while (CanAdvance &amp;&amp; char.IsLetter(Current))
                    {
                        Position++;
                    }
                    if (start != Position)
                    {
                        token = new Token { TokenType = TokenType.Identifier };
                        token.Value = Input.Substring(start, Position - start);
                    }
                    else
                    {
                        // Try and match numbers
                        while (CanAdvance &amp;&amp; char.IsDigit(Current))
                        {
                            Position++;
                        }
                        if (CanAdvance &amp;&amp; Current == '.')
                        {
                            Position++;
                        }
                        while (CanAdvance &amp;&amp; char.IsDigit(Current))
                        {
                            Position++;
                        }

                        if (start != Position)
                        {
                            token = new Token { TokenType = TokenType.Number };
                            token.Value = double.Parse(Input.Substring(start, Position - start), CultureInfo.InvariantCulture);
                        }
                    }
                }

                if (token != null)
                {
                    return token;
                }
                else if (CanAdvance)
                {
                    throw new FormatException(string.Format(CultureInfo.InvariantCulture, "Unknown token at position {0}!", Position));
                }
                else
                {
                    return null;
                }
            }

            /// &lt;summary&gt;
            /// Match a literal token.
            /// &lt;/summary&gt;
            /// &lt;param name="tokenChar"&gt;Character of the token.&lt;/param&gt;
            /// &lt;param name="tokenType"&gt;The type of the token.&lt;/param&gt;
            /// &lt;returns&gt;The literal token, if matched.&lt;/returns&gt;
            private Token MatchLiteral(char tokenChar, TokenType tokenType)
            {
                if (CanAdvance &amp;&amp; Current == tokenChar)
                {
                    Position++;
                    return new Token { TokenType = tokenType };
                }

                return null;
            }

            /// &lt;summary&gt;
            /// Get the next input token.
            /// &lt;/summary&gt;
            /// &lt;returns&gt;The next input token.&lt;/returns&gt;
            public Token Get()
            {
                Token token = null;
                if (Lookahead != null)
                {
                    token = Lookahead;
                    Lookahead = null;
                }
                else
                {
                    token = ReadNext();
                }
                return token;
            }

            /// &lt;summary&gt;
            /// Peek at the lookahead token.
            /// &lt;/summary&gt;
            /// &lt;returns&gt;The lookahead token.&lt;/returns&gt;
            public Token Peek()
            {
                if (Lookahead == null)
                {
                    Lookahead = ReadNext();
                }
                return Lookahead;
            }
        }

        /// &lt;summary&gt;
        /// Perform syntactic analysis of simple expressions.
        /// &lt;/summary&gt;
        /// &lt;remarks&gt;
        /// The parser uses the following grammar:
        ///    {Expression}
        ///         := {Term} '+' {Expression}
        ///         |  {Term} '-' {Expression}
        ///         |  {Term}
        ///    {Term}
        ///         := {Exponent} '*' {Term}
        ///         |  {Exponent} '/' {Term}
        ///         |  {Exponent}
        ///    {Exponent}
        ///         := {Factor} '^' {Exponent}
        ///         |  {Factor}
        ///    {Factor}
        ///         := {Number}
        ///         |  {Identifier}
        ///         | '(' {Expression} ')'
        /// &lt;/remarks&gt;
        private class Parser
        {
            /// &lt;summary&gt;
            /// Gets or sets the lexer used for lexical analysis.
            /// &lt;/summary&gt;
            private Lexer Lexer { get; set; }

            /// &lt;summary&gt;
            /// Gets or sets the single variable of the function.
            /// &lt;/summary&gt;
            private Sle.ParameterExpression Parameter { get; set; }

            /// &lt;summary&gt;
            /// Gets the function created from the input.
            /// &lt;/summary&gt;
            public Func&lt;double, double&gt; Function { get; private set; }

            /// &lt;summary&gt;
            /// Initializes a new instance of the Parser class.
            /// &lt;/summary&gt;
            /// &lt;param name="input"&gt;The input to analyze.&lt;/param&gt;
            public Parser(string input)
            {
                Lexer = new Lexer(input);
                Parse();
            }

            /// &lt;summary&gt;
            /// Parse the input and create a function.
            /// &lt;/summary&gt;
            private void Parse()
            {
                // Build the expression
                Sle.Expression expression = GetExpression();

                // Ensure we exhausted the input
                int finalPosition = Lexer.Position;
                Token finalToken = Lexer.Get();
                if (finalToken != null)
                {
                    throw new FormatException(string.Format(CultureInfo.InvariantCulture, "Unexpected token {0} at position {1}!", finalToken.TokenType, finalPosition));
                }

                // Wrap the expression in a function
                Sle.Expression&lt;Func&lt;double, double&gt;&gt; functionExpression =
                    Sle.Expression.Lambda&lt;Func&lt;double, double&gt;&gt;(
                        expression,
                        Parameter ?? Sle.Expression.Parameter(typeof(double), "x"));

                // Compile the expression into a function
                Function = functionExpression.Compile();
            }

            /// &lt;summary&gt;
            /// Read an expression.
            /// &lt;/summary&gt;
            /// &lt;returns&gt;The parsed expression.&lt;/returns&gt;
            private Sle.Expression GetExpression()
            {
                Sle.Expression term = GetTerm();
                if (TryMatch(TokenType.Addition))
                {
                    Sle.Expression expr = GetExpression();
                    return Sle.Expression.Add(term, expr);
                }
                else if (TryMatch(TokenType.Subtraction))
                {
                    Sle.Expression expr = GetExpression();
                    return Sle.Expression.Subtract(term, expr);
                }
                return term;
            }

            /// &lt;summary&gt;
            /// Read a term.
            /// &lt;/summary&gt;
            /// &lt;returns&gt;The parsed term.&lt;/returns&gt;
            private Sle.Expression GetTerm()
            {
                Sle.Expression exponent = GetExponent();
                if (TryMatch(TokenType.Multiplication))
                {
                    Sle.Expression term = GetTerm();
                    return Sle.Expression.Multiply(exponent, term);
                }
                else if (TryMatch(TokenType.Division))
                {
                    Sle.Expression term = GetTerm();
                    return Sle.Expression.Divide(exponent, term);
                }
                return exponent;
            }

            /// &lt;summary&gt;
            /// Read an exponent.
            /// &lt;/summary&gt;
            /// &lt;returns&gt;The parsed exponent.&lt;/returns&gt;
            private Sle.Expression GetExponent()
            {
                Sle.Expression factor = GetFactor();
                if (TryMatch(TokenType.Exponentiation))
                {
                    Sle.Expression power = GetExponent();
                    return Sle.Expression.Power(factor, power);
                }
                else
                {
                    return factor;
                }
            }

            /// &lt;summary&gt;
            /// Read a factor.
            /// &lt;/summary&gt;
            /// &lt;returns&gt;The parsed factor.&lt;/returns&gt;
            private Sle.Expression GetFactor()
            {
                Token token = Lexer.Get();
                if (token != null)
                {
                    if (token.TokenType == TokenType.Number)
                    {
                        return Sle.Expression.Constant(token.Value, typeof(double));
                    }
                    else if (token.TokenType == TokenType.Identifier)
                    {
                        string name = token.Value as string;

                        // Linq expressions use referential equality on
                        // parameters, so we need to use the same instance
                        if (Parameter != null &amp;&amp; Parameter.Name != name)
                        {
                            throw new FormatException("Only single variable functions are supported!");
                        }
                        else if (Parameter == null)
                        {
                            Parameter = Sle.Expression.Parameter(typeof(double), name);
                        }
                        return Parameter;
                    }
                    else if (token.TokenType == TokenType.LeftParenthesis)
                    {
                        Sle.Expression nested = GetExpression();
                        if (TryMatch(TokenType.RightParenthesis))
                        {
                            return nested;
                        }
                    }
                }

                throw new FormatException(string.Format(CultureInfo.InvariantCulture, "Unexpected token type at position {0}!", Lexer.Position));
            }
            
            /// &lt;summary&gt;
            /// Try to match a token.
            /// &lt;/summary&gt;
            /// &lt;param name="tokenType"&gt;The type of token to match.&lt;/param&gt;
            /// &lt;returns&gt;
            /// A value indicating whether the token was matched.
            /// &lt;/returns&gt;
            private bool TryMatch(TokenType tokenType)
            {
                Token token = Lexer.Peek();
                if (token != null &amp;&amp; token.TokenType == tokenType)
                {
                    Lexer.Get();
                    return true;
                }

                return false;
            }
        }
    }
}</sys:String>
    </src:SourceFile.Source>
  </src:SourceFile>
  <src:SourceFile Path="SimpleFunctionTypeConverter.vb">
    <src:SourceFile.Source>
      <sys:String>' (c) Copyright Microsoft Corporation.
' This source is subject to the Microsoft Public License (Ms-PL).
' Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
' All other rights reserved.

Imports Microsoft.VisualBasic
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Diagnostics
Imports System.Globalization
Imports Sle = System.Linq.Expressions
Imports System.Text

''' &lt;summary&gt;
''' TypeConverter used for creating single variable functions from simple
''' arithmetic expressions.
''' &lt;/summary&gt;
Public Class SimpleFunctionTypeConverter
    Inherits TypeConverter
    ''' &lt;summary&gt;
    ''' Initializes a new instance of the SimpleFunctionTypeConverter class.
    ''' &lt;/summary&gt;
    Public Sub New()
    End Sub

    ''' &lt;summary&gt;
    ''' Determine whether the sourceType can be converted to a single
    ''' variable function.
    ''' &lt;/summary&gt;
    ''' &lt;param name="context"&gt;Conversion context.&lt;/param&gt;
    ''' &lt;param name="sourceType"&gt;The type to convert from.&lt;/param&gt;
    ''' &lt;returns&gt;
    ''' A value indicating whether the type can be converted.
    ''' &lt;/returns&gt;
    Public Overloads Overrides Function CanConvertFrom(ByVal context As ITypeDescriptorContext, ByVal sourceType As Type) As Boolean
        Return sourceType Is GetType(String)
    End Function

    ''' &lt;summary&gt;
    ''' Convert the value into a single variable function.
    ''' &lt;/summary&gt;
    ''' &lt;param name="context"&gt;Conversion context.&lt;/param&gt;
    ''' &lt;param name="culture"&gt;Conversion culture.&lt;/param&gt;
    ''' &lt;param name="value"&gt;The value to convert.&lt;/param&gt;
    ''' &lt;returns&gt;A single variable function.&lt;/returns&gt;
    Public Overloads Overrides Function ConvertFrom(ByVal context As ITypeDescriptorContext, ByVal culture As CultureInfo, ByVal value As Object) As Object
        Dim [function] As Func(Of Double, Double) = Nothing

        Dim text As String = TryCast(value, String)
        If (Not String.IsNullOrEmpty(text)) Then
            [function] = New Parser(text).Function
        End If

        Return [function]
    End Function

    ''' &lt;summary&gt;
    ''' Defines the type of a token.
    ''' &lt;/summary&gt;
    Private Enum TokenType
        ''' &lt;summary&gt;
        ''' A numeric value..
        ''' &lt;/summary&gt;
        Number

        ''' &lt;summary&gt;
        ''' An identifier.
        ''' &lt;/summary&gt;
        Identifier

        ''' &lt;summary&gt;
        ''' The addition operator.
        ''' &lt;/summary&gt;
        Addition

        ''' &lt;summary&gt;
        ''' The substraction operator.
        ''' &lt;/summary&gt;
        Subtraction

        ''' &lt;summary&gt;
        ''' The exponentiation operator.
        ''' &lt;/summary&gt;
        Multiplication

        ''' &lt;summary&gt;
        ''' The division operator.
        ''' &lt;/summary&gt;
        Division

        ''' &lt;summary&gt;
        ''' The exponentiation operator.
        ''' &lt;/summary&gt;
        Exponentiation

        ''' &lt;summary&gt;
        ''' A left parenthesis.
        ''' &lt;/summary&gt;
        LeftParenthesis

        ''' &lt;summary&gt;
        ''' A right parenthesis.
        ''' &lt;/summary&gt;
        RightParenthesis
    End Enum

    ''' &lt;summary&gt;
    ''' Represents a lexical token.
    ''' &lt;/summary&gt;
    Private Class Token
        ''' &lt;summary&gt;
        ''' Gets or sets the type of the token.
        ''' &lt;/summary&gt;
        Private privateTokenType As TokenType
        Public Property TokenType() As TokenType
            Get
                Return privateTokenType
            End Get
            Set(ByVal value As TokenType)
                privateTokenType = value
            End Set
        End Property

        ''' &lt;summary&gt;
        ''' Gets or sets the value of a token (for numbers and identifiers).
        ''' &lt;/summary&gt;
        Private privateValue As Object
        Public Property Value() As Object
            Get
                Return privateValue
            End Get
            Set(ByVal value As Object)
                privateValue = value
            End Set
        End Property

        ''' &lt;summary&gt;
        ''' Initializes a new instance of the Token class.
        ''' &lt;/summary&gt;
        Public Sub New()
        End Sub
    End Class

    ''' &lt;summary&gt;
    ''' Perform lexical analysis of simple expressions.
    ''' &lt;/summary&gt;
    Private Class Lexer
        ''' &lt;summary&gt;
        ''' Gets or sets the input string to scan.
        ''' &lt;/summary&gt;
        Private privateInput As String
        Friend Property Input() As String
            Get
                Return privateInput
            End Get
            Set(ByVal value As String)
                privateInput = value
            End Set
        End Property

        ''' &lt;summary&gt;
        ''' Gets or sets the current position of the lexer.
        ''' &lt;/summary&gt;
        Private privatePosition As Integer
        Friend Property Position() As Integer
            Get
                Return privatePosition
            End Get
            Set(ByVal value As Integer)
                privatePosition = value
            End Set
        End Property

        ''' &lt;summary&gt;
        ''' Gets a value indicating whether the lexer has room to advance
        ''' through the input.
        ''' &lt;/summary&gt;
        Friend ReadOnly Property CanAdvance() As Boolean
            Get
                Return Position &lt; Input.Length
            End Get
        End Property

        ''' &lt;summary&gt;
        ''' Gets the character at the current input position.
        ''' &lt;/summary&gt;
        Private ReadOnly Property Current() As Char
            Get
                Return Input(Position)
            End Get
        End Property

        ''' &lt;summary&gt;
        ''' Gets or sets the lookahead token.
        ''' &lt;/summary&gt;
        Private privateLookahead As Token
        Private Property Lookahead() As Token
            Get
                Return privateLookahead
            End Get
            Set(ByVal value As Token)
                privateLookahead = value
            End Set
        End Property

        ''' &lt;summary&gt;
        ''' Initializes a new instance of the Lexer class.
        ''' &lt;/summary&gt;
        ''' &lt;param name="input"&gt;The input to analyze.&lt;/param&gt;
        Public Sub New(ByVal input As String)
            Debug.Assert((Not String.IsNullOrEmpty(input)), "input shuould not be null or empty!")
            Me.Input = input
        End Sub

        ''' &lt;summary&gt;
        ''' Advance the token to the next input.
        ''' &lt;/summary&gt;
        ''' &lt;returns&gt;The token that was read.&lt;/returns&gt;
        &lt;System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification:="Literal token matching code is consistent with C# implementation.")&gt; _
        Private Function ReadNext() As Token
            ' Eat as much whitespace as possible
            Do While CanAdvance AndAlso Char.IsWhiteSpace(Current)
                Position += 1
            Loop

            ' Match a literal token
            Dim token As Token = MatchLiteral("("c, TokenType.LeftParenthesis)
            If token Is Nothing Then
                token = MatchLiteral(")"c, TokenType.RightParenthesis)
                If token Is Nothing Then
                    token = MatchLiteral("+"c, TokenType.Addition)
                    If token Is Nothing Then
                        token = MatchLiteral("-"c, TokenType.Subtraction)
                        If token Is Nothing Then
                            token = MatchLiteral("*"c, TokenType.Multiplication)
                            If token Is Nothing Then
                                token = MatchLiteral("/"c, TokenType.Division)
                                If token Is Nothing Then
                                    token = MatchLiteral("^"c, TokenType.Exponentiation)
                                End If
                            End If
                        End If
                    End If
                End If
            End If

            ' Match identifier or number tokens
            If token Is Nothing Then
                Dim start As Integer = Position

                ' Try and match identifiers
                Do While CanAdvance AndAlso Char.IsLetter(Current)
                    Position += 1
                Loop
                If start &lt;&gt; Position Then
                    token = New Token With {.TokenType = TokenType.Identifier}
                    token.Value = Input.Substring(start, Position - start)
                Else
                    ' Try and match numbers
                    Do While CanAdvance AndAlso Char.IsDigit(Current)
                        Position += 1
                    Loop
                    If CanAdvance AndAlso Current = "."c Then
                        Position += 1
                    End If
                    Do While CanAdvance AndAlso Char.IsDigit(Current)
                        Position += 1
                    Loop

                    If start &lt;&gt; Position Then
                        token = New Token With {.TokenType = TokenType.Number}
                        token.Value = Double.Parse(Input.Substring(start, Position - start), CultureInfo.InvariantCulture)
                    End If
                End If
            End If

            If token IsNot Nothing Then
                Return token
            ElseIf CanAdvance Then
                Throw New FormatException(String.Format(CultureInfo.InvariantCulture, "Unknown token at position {0}!", Position))
            Else
                Return Nothing
            End If
        End Function

        ''' &lt;summary&gt;
        ''' Match a literal token.
        ''' &lt;/summary&gt;
        ''' &lt;param name="tokenChar"&gt;Character of the token.&lt;/param&gt;
        ''' &lt;param name="tokenType"&gt;The type of the token.&lt;/param&gt;
        ''' &lt;returns&gt;The literal token, if matched.&lt;/returns&gt;
        Private Function MatchLiteral(ByVal tokenChar As Char, ByVal tokenType As TokenType) As Token
            If CanAdvance AndAlso Current = tokenChar Then
                Position += 1
                Return New Token With {.TokenType = tokenType}
            End If

            Return Nothing
        End Function

        ''' &lt;summary&gt;
        ''' Get the next input token.
        ''' &lt;/summary&gt;
        ''' &lt;returns&gt;The next input token.&lt;/returns&gt;
        Public Function [Get]() As Token
            Dim token As Token = Nothing
            If Lookahead IsNot Nothing Then
                token = Lookahead
                Lookahead = Nothing
            Else
                token = ReadNext()
            End If
            Return token
        End Function

        ''' &lt;summary&gt;
        ''' Peek at the lookahead token.
        ''' &lt;/summary&gt;
        ''' &lt;returns&gt;The lookahead token.&lt;/returns&gt;
        Public Function Peek() As Token
            If Lookahead Is Nothing Then
                Lookahead = ReadNext()
            End If
            Return Lookahead
        End Function
    End Class

    ''' &lt;summary&gt;
    ''' Perform syntactic analysis of simple expressions.
    ''' &lt;/summary&gt;
    ''' &lt;remarks&gt;
    ''' The parser uses the following grammar:
    '''    {Expression}
    '''         := {Term} '+' {Expression}
    '''         |  {Term} '-' {Expression}
    '''         |  {Term}
    '''    {Term}
    '''         := {Exponent} '*' {Term}
    '''         |  {Exponent} '/' {Term}
    '''         |  {Exponent}
    '''    {Exponent}
    '''         := {Factor} '^' {Exponent}
    '''         |  {Factor}
    '''    {Factor}
    '''         := {Number}
    '''         |  {Identifier}
    '''         | '(' {Expression} ')'
    ''' &lt;/remarks&gt;
    Private Class Parser
        ''' &lt;summary&gt;
        ''' Gets or sets the lexer used for lexical analysis.
        ''' &lt;/summary&gt;
        Private privateLexer As Lexer
        Private Property Lexer() As Lexer
            Get
                Return privateLexer
            End Get
            Set(ByVal value As Lexer)
                privateLexer = value
            End Set
        End Property

        ''' &lt;summary&gt;
        ''' Gets or sets the single variable of the function.
        ''' &lt;/summary&gt;
        Private privateParameter As Sle.ParameterExpression
        Private Property Parameter() As Sle.ParameterExpression
            Get
                Return privateParameter
            End Get
            Set(ByVal value As Sle.ParameterExpression)
                privateParameter = value
            End Set
        End Property

        ''' &lt;summary&gt;
        ''' Gets the function created from the input.
        ''' &lt;/summary&gt;
        Private privateFunction As Func(Of Double, Double)
        Public Property [Function]() As Func(Of Double, Double)
            Get
                Return privateFunction
            End Get
            Private Set(ByVal value As Func(Of Double, Double))
                privateFunction = value
            End Set
        End Property

        ''' &lt;summary&gt;
        ''' Initializes a new instance of the Parser class.
        ''' &lt;/summary&gt;
        ''' &lt;param name="input"&gt;The input to analyze.&lt;/param&gt;
        Public Sub New(ByVal input As String)
            Lexer = New Lexer(input)
            Parse()
        End Sub

        ''' &lt;summary&gt;
        ''' Parse the input and create a function.
        ''' &lt;/summary&gt;
        Private Sub Parse()
            ' Continue only if there is something to parse
            If Not Lexer.CanAdvance Then
                Return
            End If

            ' Build the expression
            Dim expression As Sle.Expression = GetExpression()

            ' Ensure we exhausted the input
            Dim finalPosition As Integer = Lexer.Position
            Dim finalToken As Token = Lexer.Get()
            If finalToken IsNot Nothing Then
                Throw New FormatException(String.Format(CultureInfo.InvariantCulture, "Unexpected token {0} at position {1}!", finalToken.TokenType, finalPosition))
            End If

            ' Wrap the expression in a function
            Dim functionExpression As Sle.Expression(Of Func(Of Double, Double)) = _
                Sle.Expression.Lambda(Of Func(Of Double, Double))( _
                    expression, _
                    If(Parameter IsNot Nothing, Parameter, Sle.Expression.Parameter(GetType(Double), "x")))

            ' Compile the expression into a function
            [Function] = functionExpression.Compile()
        End Sub

        ''' &lt;summary&gt;
        ''' Read an expression.
        ''' &lt;/summary&gt;
        ''' &lt;returns&gt;The parsed expression.&lt;/returns&gt;
        Private Function GetExpression() As Sle.Expression
            Dim term As Sle.Expression = GetTerm()
            If Lexer.CanAdvance AndAlso TryMatch(TokenType.Addition) Then
                Dim expr As Sle.Expression = GetExpression()
                Return Sle.Expression.Add(term, expr)
            ElseIf Lexer.CanAdvance AndAlso TryMatch(TokenType.Subtraction) Then
                Dim expr As Sle.Expression = GetExpression()
                Return Sle.Expression.Subtract(term, expr)
            End If
            Return term
        End Function

        ''' &lt;summary&gt;
        ''' Read a term.
        ''' &lt;/summary&gt;
        ''' &lt;returns&gt;The parsed term.&lt;/returns&gt;
        Private Function GetTerm() As Sle.Expression
            Dim exponent As Sle.Expression = GetExponent()
            If Lexer.CanAdvance AndAlso TryMatch(TokenType.Multiplication) Then
                Dim term As Sle.Expression = GetTerm()
                Return Sle.Expression.Multiply(exponent, term)
            ElseIf Lexer.CanAdvance AndAlso TryMatch(TokenType.Division) Then
                Dim term As Sle.Expression = GetTerm()
                Return Sle.Expression.Divide(exponent, term)
            End If
            Return exponent
        End Function

        ''' &lt;summary&gt;
        ''' Read an exponent.
        ''' &lt;/summary&gt;
        ''' &lt;returns&gt;The parsed exponent.&lt;/returns&gt;
        Private Function GetExponent() As Sle.Expression
            Dim factor As Sle.Expression = GetFactor()
            If Lexer.CanAdvance AndAlso TryMatch(TokenType.Exponentiation) Then
                Dim power As Sle.Expression = GetExponent()
                Return Sle.Expression.Power(factor, power)
            Else
                Return factor
            End If
        End Function

        ''' &lt;summary&gt;
        ''' Read a factor.
        ''' &lt;/summary&gt;
        ''' &lt;returns&gt;The parsed factor.&lt;/returns&gt;
        Private Function GetFactor() As Sle.Expression
            Dim token As Token = Lexer.Get()
            If token IsNot Nothing Then
                If token.TokenType = TokenType.Number Then
                    Return Sle.Expression.Constant(token.Value, GetType(Double))
                ElseIf token.TokenType = TokenType.Identifier Then
                    Dim name As String = TryCast(token.Value, String)

                    ' Linq expressions use referential equality on
                    ' parameters, so we need to use the same instance
                    If Parameter IsNot Nothing AndAlso Parameter.Name &lt;&gt; name Then
                        Throw New FormatException("Only single variable functions are supported!")
                    ElseIf Parameter Is Nothing Then
                        Parameter = Sle.Expression.Parameter(GetType(Double), name)
                    End If
                    Return Parameter
                ElseIf Lexer.CanAdvance AndAlso token.TokenType = TokenType.LeftParenthesis Then
                    Dim nested As Sle.Expression = GetExpression()
                    If TryMatch(TokenType.RightParenthesis) Then
                        Return nested
                    End If
                End If
            End If

            Throw New FormatException(String.Format(CultureInfo.InvariantCulture, "Unexpected token type at position {0}!", Lexer.Position))
        End Function

        ''' &lt;summary&gt;
        ''' Try to match a token.
        ''' &lt;/summary&gt;
        ''' &lt;param name="tokenType"&gt;The type of token to match.&lt;/param&gt;
        ''' &lt;returns&gt;
        ''' A value indicating whether the token was matched.
        ''' &lt;/returns&gt;
        Private Function TryMatch(ByVal tokenType As TokenType) As Boolean
            Dim token As Token = Lexer.Peek()
            If token IsNot Nothing AndAlso token.TokenType = tokenType Then
                Lexer.Get()
                Return True
            End If

            Return False
        End Function
    End Class
End Class
</sys:String>
    </src:SourceFile.Source>
  </src:SourceFile>
</src:SourceViewer>
    </StackPanel>
</UserControl>
